home *** CD-ROM | disk | FTP | other *** search
/ User's Choice Windows CD / User's Choice Windows CD (CMS Software)(1993).iso / utility3 / makemdi2.zip / FRAME.C < prev    next >
C/C++ Source or Header  |  1992-11-25  |  31KB  |  1,110 lines

  1. #define _FRAME_C
  2. //----------------------------------------------------------------- 
  3. // APP.C - <description> 
  4. // 
  5. // MAKEMDI adaptation of Windows 3.1 SDK MAKEAPP system. 
  6. // 
  7. // MDI application design based on Chapter 7 of     
  8. // "Windows 3: A Developer's Guide" by Jeffrey Richter. 
  9. // 
  10. // Adaptation developed with permission of the author by  
  11. // John F. Holliday, Technisoft Corporation 
  12. // Telephone: (515) 472-9803, CompuServe: 71271,634
  13. //
  14. // [DMM]    25-Nov-1992: Fixed crashing on exit
  15. //            Also tabified file to tabsize of 4
  16. //
  17. //            David M. Miller, Business Visions, Inc.
  18. //            Telephone: (212) 747-6118
  19. //            CompuServe: 72676,327
  20. //            internet: dmiller@hera.sbi.com
  21. //----------------------------------------------------------------- 
  22. #include "makemdi.h"
  23.  
  24.  
  25. BOOL Frame_Initialize(APP * papp)
  26. {
  27.     WNDCLASS cls;
  28.  
  29.     cls.hCursor = LoadCursor(NULL, IDC_ARROW);
  30.     cls.hIcon = LoadIcon(papp->hinst, MAKEINTRESOURCE(IDR_FRAMEICON));
  31.     cls.lpszMenuName = MAKEINTRESOURCE(IDR_FRAMEMENU);
  32.     cls.hInstance = papp->hinst;
  33.     cls.lpszClassName = CLASS_FRAME;
  34.     cls.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
  35.     cls.lpfnWndProc = Frame_WndProc;
  36.     cls.style = CS_HREDRAW | CS_VREDRAW;
  37.     cls.cbWndExtra = sizeof(FRAME *);
  38.     cls.cbClsExtra = 0;
  39.  
  40.     if (!RegisterClass(&cls))
  41.         return FALSE;
  42.  
  43.     return TRUE;
  44. }
  45.  
  46. void Frame_Terminate(APP * papp)
  47. {
  48. }
  49.  
  50. LRESULT CALLBACK _export Frame_WndProc(HWND hWnd,
  51.                                        UINT msg,
  52.                                        WPARAM wParam,
  53.                                        LPARAM lParam)
  54. {
  55.     LRESULT lResult = 0;
  56.     FRAME *pfrm = Frame_GetPtr(hWnd);
  57.  
  58.     if (pfrm == NULL) {
  59.         if (msg == WM_NCCREATE) {
  60.             pfrm = (FRAME *) LocalAlloc(LPTR, sizeof(FRAME));
  61.  
  62.             if (pfrm == NULL)
  63.                 return (LRESULT) FALSE;
  64.  
  65.             pfrm->hWnd = hWnd;
  66.             Frame_SetPtr(hWnd, pfrm);
  67.         }
  68.         else
  69.             return DefWindowProc(hWnd, msg, wParam, lParam);
  70.     }
  71.  
  72.     if (msg == WM_NCDESTROY) {
  73.         // [DMM] Added: save hwndClient before freeing pfrm
  74.         HWND hWndClient = pfrm->hWndClient;
  75.  
  76.         if (pfrm->fpProcRibbon != NULL)
  77.             FreeProcInstance((FARPROC) pfrm->fpProcRibbon);
  78.  
  79.         if (pfrm->hMenu != NULL)
  80.             DestroyMenu(pfrm->hMenu);
  81.  
  82.         LocalFree((HLOCAL)OFFSETOF(pfrm));
  83.         pfrm = NULL;
  84.         Frame_SetPtr(hWnd, NULL);
  85.  
  86.         // [DMM] Added: execution ends here on NCDESTROY
  87.         return DefFrameProc(hWnd, hWndClient, msg, wParam, lParam);
  88.     }
  89.  
  90.  
  91.     // Get the window handle of the active MDI child. 
  92.     // This is NULL if no MDI children exist. 
  93.     // Determine if the MDI child is maximized. 
  94.  
  95.     if (IsWindow(pfrm->hWndClient))
  96.         lResult = SendMessage(pfrm->hWndClient, WM_MDIGETACTIVE, 0, 0);
  97.  
  98.     pfrm->hWndActiveMDIChild = (HWND) LOWORD(lResult);
  99.     pfrm->fMDIChildIsMaximized = HIWORD(lResult);
  100.  
  101.  
  102.     switch (msg) {
  103.         // Windows messages 
  104.  
  105.         HANDLE_MSG(pfrm, WM_CREATE, Frame_OnCreate);
  106.         HANDLE_MSG(pfrm, WM_DESTROY, Frame_OnDestroy);
  107.         HANDLE_MSG(pfrm, WM_CLOSE, Frame_OnClose);
  108.         HANDLE_MSG(pfrm, WM_QUERYENDSESSION, Frame_OnQueryEndSession);
  109.         HANDLE_MSG(pfrm, WM_ENDSESSION, Frame_OnEndSession);
  110.         HANDLE_MSG(pfrm, WM_PAINT, Frame_OnPaint);
  111.         HANDLE_MSG(pfrm, WM_ERASEBKGND, Frame_OnEraseBkgnd);
  112.         HANDLE_MSG(pfrm, WM_SIZE, Frame_OnSize);
  113.         HANDLE_MSG(pfrm, WM_ACTIVATE, Frame_OnActivate);
  114.         HANDLE_MSG(pfrm, WM_INITMENU, Frame_OnInitMenu);
  115.         HANDLE_MSG(pfrm, WM_INITMENUPOPUP, Frame_OnInitMenuPopup);
  116.         HANDLE_MSG(pfrm, WM_COMMAND, Frame_OnCommand);
  117.  
  118.         HANDLE_MSG(pfrm, WM_SYSCOMMAND, Frame_OnSysCommand);
  119.         HANDLE_MSG(pfrm, WM_NCLBUTTONDBLCLK, Frame_OnNclButtonDown);
  120.         HANDLE_MSG(pfrm, WM_MENUSELECT, Frame_OnMenuSelect);
  121.         HANDLE_MSG(pfrm, WM_ENTERIDLE, Frame_OnEnterIdle);
  122.  
  123.         // Frame window specific messages 
  124.  
  125.         HANDLE_MSG(pfrm, FW_MDICHILDDESTROY, Frame_OnMdiChildDestroy);
  126.         HANDLE_MSG(pfrm, FW_GETSTATBARRECT, Frame_OnGetStatBarRect);
  127.         HANDLE_MSG(pfrm, FW_DRAWSTATUSDIVIDE, Frame_OnDrawStatusDivide);
  128.         HANDLE_MSG(pfrm, FW_RESIZEMDICLIENT, Frame_OnResizeMdiClient);
  129.         HANDLE_MSG(pfrm, FW_SETMENUHELP, Frame_OnSetMenuHelp);
  130.         HANDLE_MSG(pfrm, FW_GETMENUHELP, Frame_OnGetMenuHelp);
  131.  
  132.         // Application messages 
  133.  
  134.         HANDLE_MSG(pfrm, AW_PAINTMENUHELP, Frame_OnPaintMenuHelp);
  135.  
  136.     default:
  137.         return DefFrameProc(hWnd, pfrm->hWndClient, msg, wParam, lParam);
  138.     }
  139. }
  140.  
  141. HWND Frame_CreateWindow(LPCSTR lpszText,
  142.                         int x,
  143.                         int y,
  144.                         int cx,
  145.                         int cy,
  146.                         HINSTANCE hinst)
  147. {
  148.     return CreateWindowEx(0L,
  149.                           CLASS_FRAME,
  150.                           lpszText,
  151.             WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
  152.                           x, y, cx, cy,
  153.                           NULL,
  154.                           NULL,
  155.                           hinst,
  156.                           NULL);
  157. }
  158.  
  159. //-Message handlers------------------------------------------------ 
  160.  
  161. BOOL Frame_OnCreate(FRAME * pfrm, CREATESTRUCT FAR * lpCreateStruct)
  162. {
  163.     CLIENTCREATESTRUCT ccs;
  164.  
  165.     pfrm->hMenu = LoadMenu(lpCreateStruct->hInstance,
  166.                            MAKEINTRESOURCE(IDR_FRAMEMENU));
  167.  
  168.     pfrm->fStatusBarOn = TRUE;
  169.  
  170.     // Create the MDICLIENT window as a child of the frame. 
  171.  
  172.     ccs.hWindowMenu = GetSubMenu(GetMenu(pfrm->hWnd), 1);
  173.     ccs.idFirstChild = CMD_WINDOWCHILD;
  174.  
  175.     pfrm->hWndClient = CreateWindow("MDIClient", "",
  176.                         WS_CHILD | WS_CLIPCHILDREN | WS_VSCROLL | WS_HSCROLL |
  177.                                     WS_VISIBLE | WS_CLIPSIBLINGS, 0, 0, 0, 0,
  178.                                   pfrm->hWnd, NULL, lpCreateStruct->hInstance,
  179.                                     (LPSTR) (LPCLIENTCREATESTRUCT) & ccs);
  180.  
  181.     // Create the Ribbon dialog box with Frame as owner. 
  182.  
  183.     pfrm->fpProcRibbon = (DLGPROC) MakeProcInstance((FARPROC) Ribbon_DlgProc, g_app.hinst);
  184.  
  185.     pfrm->hdlgRibbon = CreateDialog(g_app.hinst,
  186.                                     MAKEINTRESOURCE(DLG_RIBBON), pfrm->hWnd,
  187.                                     pfrm->fpProcRibbon);
  188.  
  189.     if (pfrm->hdlgRibbon == NULL) {
  190.         FreeProcInstance((FARPROC) pfrm->fpProcRibbon);
  191.         return (0);
  192.     }
  193.  
  194.     return pfrm->hWndClient != NULL;
  195. }
  196.  
  197. void Frame_OnDestroy(FRAME * pfrm)
  198. {
  199.     PostQuitMessage(0);
  200. }
  201.  
  202. void Frame_OnClose(FRAME * pfrm)
  203. {
  204.     // Before closing the application, ask the MDI children if it 
  205.     // is ok? 
  206.  
  207.     if ((BOOL) SendMessage(pfrm->hWnd, WM_QUERYENDSESSION, 0, 0)) {
  208.         SendMessage(pfrm->hWnd, WM_ENDSESSION, TRUE, 0);
  209.         DefFrameProc(pfrm->hWnd, pfrm->hWndClient, WM_CLOSE, 0, 0L);
  210.     }
  211. }
  212.  
  213. BOOL Frame_OnQueryEndSession(FRAME * pfrm)
  214. {
  215.     BOOL            bResult = TRUE;
  216.     HWND            hWndChild;
  217.  
  218.     // Get the handle of the first MDI Child. 
  219.  
  220.     hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
  221.  
  222.     if (hWndChild != NULL) {
  223.         // Ask each child if it is OK to terminate. 
  224.  
  225.         do {
  226.             // Do not ask caption bars of iconic MDI Children. 
  227.  
  228.             if (GetWindow(hWndChild, GW_OWNER) != NULL)
  229.                 continue;
  230.  
  231.             bResult = FORWARD_WM_QUERYENDSESSION(hWndChild, SendMessage);
  232.  
  233.             // If the MDI Child says that it is NOT OK, don't ask the 
  234.             // rest of the MDI Children. 
  235.  
  236.             if (bResult == FALSE)
  237.                 break;
  238.         }
  239.         while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
  240.  
  241.  
  242.         // If any MDI Child said NO, tell the other children that 
  243.         // the session is NOT being terminated. 
  244.  
  245.         if (bResult == FALSE) {
  246.             HWND            hWndTemp = hWndChild;
  247.  
  248.             hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
  249.  
  250.             do {
  251.                 // If this child is the one that said NO, stop. 
  252.  
  253.                 if (hWndTemp == hWndChild)
  254.                     break;
  255.  
  256.                 // Do not send to caption bars of iconic MDI Children. 
  257.  
  258.                 if (GetWindow(hWndChild, GW_OWNER) != NULL)
  259.                     continue;
  260.  
  261.                 // Tell child we are not ending the session (wParam is FALSE). 
  262.  
  263.                 SendMessage(hWndChild, WM_ENDSESSION, FALSE, 0);
  264.             }
  265.             while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
  266.         }
  267.  
  268.     }
  269.  
  270.     return bResult;
  271. }
  272.  
  273. void Frame_OnEndSession(FRAME * pfrm, BOOL fEnding)
  274. {
  275.     HWND            hWndChild;
  276.  
  277.     // Get handle of first MDI Child window. 
  278.  
  279.     hWndChild = GetWindow(pfrm->hWndClient, GW_CHILD);
  280.  
  281.     // If no MDI Children exist, we are done. 
  282.  
  283.     if (hWndChild != NULL) {
  284.         // Tell each MDI Child whether or not the session is ending. 
  285.  
  286.         do {
  287.             // Do not send to caption bars of iconic MDI Children. 
  288.  
  289.             if (GetWindow(hWndChild, GW_OWNER) != NULL)
  290.                 continue;
  291.  
  292.             FORWARD_WM_ENDSESSION(hWndChild, fEnding, SendMessage);
  293.         }
  294.         while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
  295.     }
  296. }
  297.  
  298. void Frame_OnPaint(FRAME * pfrm)
  299. {
  300.     PAINTSTRUCT        ps;
  301.  
  302.     // Since the only visible portion of the Frame's client area is     
  303.     // the status bar when it is ON, this must mean that the status 
  304.     // bar needs to be repainted. 
  305.  
  306.     // Set up the device context. 
  307.  
  308.     BeginPaint(pfrm->hWnd, &ps);
  309.  
  310.     SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&ps.rcPaint));
  311.     SetBkMode(ps.hdc, TRANSPARENT);
  312.  
  313.     // If an MDI Child exists, the status bar must be updated by it. 
  314.  
  315.     if (pfrm->hWndActiveMDIChild) {
  316.         SendMessage(   pfrm->hWndActiveMDIChild,
  317.                        AC_PAINTSTATBAR,
  318.                        (WPARAM) ps.hdc,
  319.                        (LPARAM)((LPPAINTSTRUCT)&ps));
  320.     }
  321.     else {
  322.         // No MDI Child exists, the Frame can do whatever it wants here. 
  323.  
  324.         ps.rcPaint.top += (int) SendMessage(pfrm->hWnd, FW_DRAWSTATUSDIVIDE, 0,
  325.                                             (LPARAM)((LPPAINTSTRUCT)&ps));
  326.  
  327.         LoadString(g_app.hinst, IDS_FRAMESTATUSBAR, g_app.szBuf, sizeof(g_app.szBuf));
  328.         TextOut(ps.hdc, 0, ps.rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
  329.     }
  330.  
  331.     EndPaint(pfrm->hWnd, &ps);
  332. }
  333.  
  334. BOOL Frame_OnEraseBkgnd(FRAME * pfrm, HDC hdc)
  335. {
  336.     return FORWARD_WM_ERASEBKGND(pfrm->hWnd, hdc, DefWindowProc);
  337. }
  338.  
  339. void Frame_OnSize(FRAME * pfrm, UINT state, int cx, int cy)
  340. //----------------------------------------------------------------- 
  341. // Force MDICHILD window to be resized. 
  342. //----------------------------------------------------------------- 
  343. {
  344.     SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
  345. }
  346.  
  347. void Frame_OnActivate(FRAME * pfrm, UINT state, HWND hWndActDeact, BOOL fMinimized)
  348. {
  349.     switch (state) {
  350.     case WA_INACTIVE:
  351.         break;
  352.  
  353.     case WA_ACTIVE:
  354.         SetFocus(pfrm->hWndClient);
  355.         break;
  356.  
  357.     case WA_CLICKACTIVE:
  358.         break;
  359.     }
  360. }
  361.  
  362. void Frame_OnInitMenu(FRAME * pfrm, HMENU hMenu)
  363. //----------------------------------------------------------------- 
  364. // The user has entered the menu system, set any options. 
  365. //----------------------------------------------------------------- 
  366. {
  367.     CheckMenuItem(hMenu, CMD_OPTIONSSTATUS, MF_BYCOMMAND |
  368.             (pfrm->fStatusBarOn ? MF_CHECKED : MF_UNCHECKED));
  369.  
  370.     CheckMenuItem(hMenu, CMD_OPTIONSRIBBON, MF_BYCOMMAND |
  371.             (IsWindowVisible(pfrm->hdlgRibbon) ? MF_CHECKED : MF_UNCHECKED));
  372. }
  373.  
  374. void Frame_OnInitMenuPopup(FRAME * pfrm, HMENU hMenu, int item, BOOL fSystemMenu)
  375. {
  376. }
  377.  
  378. void Frame_OnCommand(FRAME * pfrm, int id, HWND hWndCtl, UINT code)
  379. {
  380.     BOOL            fCallDefProc = FALSE;
  381.     WORD            wTemp;
  382.  
  383.     // If a child is being activated via the "Window" menu, let 
  384.     // the DefFrameProc handle it. 
  385.  
  386.     if (id >= CMD_WINDOWCHILD)
  387.         fCallDefProc = TRUE;
  388.     else
  389.         switch (id) {
  390.         case CMD_FILEOPENSHEET:
  391.             // Get the # of sheets already created and increment by 1. 
  392.  
  393.             wTemp = pfrm->wNumSheets + 1;
  394.             pfrm->wNumSheets = wTemp;
  395.  
  396.             // The sheet's caption should display the sheet number. 
  397.  
  398.             wsprintf(g_app.szBuf, "Sheet%d", wTemp);
  399.  
  400.             // Create the MDI Child window. 
  401.  
  402.             Frame_CreateMDIChild(CLASS_SHEET, g_app.szBuf, 0,
  403.                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  404.                                  pfrm->hWndClient, g_app.hinst, 0);
  405.  
  406.             // Make sure the ribbon is enabled when any children exist. 
  407.  
  408.             EnableWindow(pfrm->hdlgRibbon, TRUE);
  409.             break;
  410.  
  411.         case CMD_FILEOPENCHART:
  412.             // Get the # of charts already created and increment by 1. 
  413.  
  414.             wTemp = pfrm->wNumCharts + 1;
  415.             pfrm->wNumCharts = wTemp;
  416.  
  417.             // The chart's caption should display the chart number. 
  418.  
  419.             wsprintf(g_app.szBuf, "Chart%d", wTemp);
  420.  
  421.             // Create the MDI Child window. 
  422.  
  423.             Frame_CreateMDIChild(CLASS_CHART, g_app.szBuf, 0,
  424.                    CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
  425.                                  pfrm->hWndClient, g_app.hinst, 0);
  426.  
  427.             // Make sure the ribbon is enabled when any children exist. 
  428.  
  429.             EnableWindow(pfrm->hdlgRibbon, TRUE);
  430.             break;
  431.  
  432.         case CMD_OPTIONSSTATUS:
  433.             // Toggle the status of the status bar, resize the MDICLIENT. 
  434.  
  435.             pfrm->fStatusBarOn = !pfrm->fStatusBarOn;
  436.             SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
  437.             break;
  438.  
  439.         case CMD_OPTIONSRIBBON:
  440.             // Toggle the status of the ribbon, resize the MDICLIENT. 
  441.  
  442.             ShowWindow(pfrm->hdlgRibbon,
  443.                        IsWindowVisible(pfrm->hdlgRibbon) ? SW_HIDE : SW_SHOW);
  444.  
  445.             SendMessage(pfrm->hWnd, FW_RESIZEMDICLIENT, 0, 0);
  446.             break;
  447.  
  448.         case CMD_EXIT:
  449.             SendMessage(pfrm->hWnd, WM_CLOSE, 0, 0L);
  450.             break;
  451.  
  452.         case CMD_HELPINDEX:
  453.         case CMD_HELPKEYBOARD:
  454.         case CMD_HELPCOMMANDS:
  455.         case CMD_HELPPROCEDURES:
  456.         case CMD_HELPUSINGHELP:
  457.             MessageBox(pfrm->hWnd, "Option not implemented.", g_app.szName, MB_OK);
  458.             break;
  459.  
  460.             // case CMD_ABOUT: 
  461.             // { 
  462.             // FARPROC    fpProc; 
  463.             // fpProc = MakeProcInstance(AboutProc, g_app.hinst); 
  464.             // DialogBox(g_app.hinst, "About", pfrm->hWnd, fpProc); 
  465.             // FreeProcInstance(fpProc); 
  466.             // break; 
  467.             // } 
  468.  
  469.         case CMD_WINDOWTILEVERT:
  470.             // Call our own function to perform vertical tiling. 
  471.  
  472.             Frame_TileVertically(pfrm->hWndClient);
  473.             break;
  474.  
  475.         case CMD_WINDOWTILEHORIZ:
  476.             // Let the MDICLIENT window do the repositioning. 
  477.  
  478.             SendMessage(pfrm->hWndClient, WM_MDITILE, 0, 0);
  479.             break;
  480.  
  481.         case CMD_WINDOWCASCADE:
  482.             // Let the MDICLIENT window do the repositioning. 
  483.  
  484.             SendMessage(pfrm->hWndClient, WM_MDICASCADE, 0, 0);
  485.             break;
  486.  
  487.         case CMD_WINDOWARRANGEICONS:
  488.             // Let the MDICLIENT window do the repositioning. 
  489.  
  490.             SendMessage(pfrm->hWndClient, WM_MDIICONARRANGE, 0, 0);
  491.             break;
  492.  
  493.         default:
  494.             // Menu options not processed by the Frame window must 
  495.             // be passed to the MDI Children for processing. 
  496.  
  497.             FORWARD_WM_COMMAND(pfrm->hWndActiveMDIChild,
  498.                                id, hWndCtl, code,
  499.                                SendMessage);
  500.             break;
  501.         }
  502.  
  503.     if (fCallDefProc)
  504.         DefFrameProc(pfrm->hWnd,
  505.                      pfrm->hWndClient, WM_COMMAND,
  506.                      (WPARAM) id, MAKELPARAM(hWndCtl, code));
  507. }
  508.  
  509. void Frame_OnSysCommand(FRAME * pfrm, WORD cmd, int x, int y)
  510. //----------------------------------------------------------------- 
  511. // Set focus to frame window.  This causes any comboboxes 
  512. // in the ribbon to be closed. 
  513. //----------------------------------------------------------------- 
  514. {
  515.     SetFocus(pfrm->hWnd);
  516.     DefFrameProc(pfrm->hWnd,
  517.                  pfrm->hWndClient, WM_SYSCOMMAND,
  518.                  (WPARAM) cmd,
  519.                  MAKELPARAM(x, y));
  520. }
  521.  
  522. void Frame_OnNclButtonDown(FRAME * pfrm, BOOL fDoubleClick, int x, int y, UINT codeHitTest)
  523. //----------------------------------------------------------------- 
  524. // Code to allow double-clicking the MDI Child's system menu 
  525. // to close the MDI Child window. 
  526. //----------------------------------------------------------------- 
  527. {
  528.     RECT            rc;
  529.     BITMAP            Bitmap;
  530.     HBITMAP            hBitmap;
  531.     DWORD            dwResult;
  532.     LPARAM            lParam;
  533.     BOOL            fCallDefProc = TRUE;
  534.  
  535.  
  536.     if (fDoubleClick && (codeHitTest == HTMENU)) {
  537.         // If the active child is not maximized, nothing to do. 
  538.  
  539.         dwResult = SendMessage(pfrm->hWndClient, WM_MDIGETACTIVE, 0, 0);
  540.  
  541.         if (HIWORD(dwResult) == 1) {
  542.             // Get position and dimensions of the MDI Child's system menu in  
  543.             // the Frame's menu bar. 
  544.  
  545.             // Get position and dimensions of the Frame window. 
  546.  
  547.             GetWindowRect(pfrm->hWnd, &rc);
  548.  
  549.             // Get handle to the CLOSE BOX bitmaps. 
  550.  
  551.             hBitmap = LoadBitmap(NULL, MAKEINTRESOURCE(OBM_CLOSE));
  552.  
  553.             // Get dimensions of the bitmaps. 
  554.  
  555.             GetObject(hBitmap, sizeof(BITMAP), (LPSTR) (LPBITMAP) & Bitmap);
  556.             DeleteBitmap(hBitmap);
  557.  
  558.             // Adjust the rectangle. 
  559.  
  560.             rc.top += GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYFRAME);
  561.             rc.bottom = rc.top + Bitmap.bmHeight;
  562.             rc.left += GetSystemMetrics(SM_CXFRAME);
  563.  
  564.             // The close bitmap includes the Application and MDI Child CLOSE  
  565.             // boxes.  So we only want half of the bitmap's width. 
  566.  
  567.             rc.right = rc.left + Bitmap.bmWidth / 2;
  568.  
  569.             // If the mouse cursor is within this rectangle, tell the  
  570.             // MDI Child window to close. 
  571.  
  572.             lParam = MAKELPARAM(x, y);
  573.             if (PtInRect(&rc, MAKEPOINT(lParam))) {
  574.                 SendMessage((HWND) LOWORD(dwResult),
  575.                             WM_SYSCOMMAND, SC_CLOSE, lParam);
  576.                 fCallDefProc = FALSE;
  577.             }
  578.         }
  579.     }
  580.  
  581.     if (fCallDefProc)
  582.         DefFrameProc(pfrm->hWnd,
  583.                      pfrm->hWndClient,
  584.                      (fDoubleClick) ? WM_NCLBUTTONDBLCLK : WM_NCLBUTTONDOWN,
  585.                      (WPARAM) (UINT) codeHitTest,
  586.                      MAKELPARAM(x, y));
  587. }
  588.  
  589. void Frame_OnMenuSelect(FRAME * pfrm, HMENU hMenu, int item, HMENU hMenuPopup, UINT flags)
  590. //----------------------------------------------------------------- 
  591. // The user has highlighted a menu item. 
  592. //----------------------------------------------------------------- 
  593. {
  594.     WORD            wTemp;
  595.  
  596.     if (flags == -1 && (hMenu == (HMENU) 0)) {
  597.         // User has stopped using the menu system. 
  598.  
  599.         SendMessage(pfrm->hWnd, FW_SETMENUHELP, 0, 0);
  600.         return;
  601.     }
  602.  
  603.     // If wTemp == 0, at end of switch, MDI Child handled the message. 
  604.  
  605.     wTemp = 0;
  606.  
  607.     switch (flags & (MF_POPUP | MF_SYSMENU)) {
  608.     case 0:
  609.         // item is a menu item ID NOT on the app's system menu. 
  610.  
  611.         if (pfrm->hWndActiveMDIChild != NULL) {
  612.             // An MDI Child exists. 
  613.  
  614.             if (pfrm->fMDIChildIsMaximized) {
  615.                 // If menu item from the MDI Child's system menu, set  
  616.                 // the MF_SYSMENU bit in the lParam parameter. 
  617.  
  618.                 HMENU            hTemp = GetSubMenu(GetMenu(pfrm->hWnd), 0);
  619.  
  620.                 if ((int) GetMenuState(hTemp, item, MF_BYCOMMAND) != -1)
  621.                     flags |= MF_SYSMENU;
  622.             }
  623.  
  624.             // Make active MDI Child think that it received the     
  625.             // WM_MENUSELECT message. 
  626.  
  627.             FORWARD_WM_MENUSELECT(
  628.                                      pfrm->hWndActiveMDIChild,
  629.                                      hMenu, item, hMenuPopup,
  630.                                      flags,
  631.                                      SendMessage);
  632.  
  633.             wTemp = 0;                    // MDI Child handled the message. 
  634.             break;
  635.         }
  636.  
  637.         wTemp = IDS_FRAMEMENUID + item;
  638.         break;
  639.  
  640.     case MF_POPUP:
  641.  
  642.         if (pfrm->hWndActiveMDIChild != NULL) {
  643.             // An MDI Child exists. 
  644.  
  645.             if (pfrm->fMDIChildIsMaximized) {
  646.                 // If popup menu is first top-level menu, it is the     
  647.                 // MDI Child's system menu, set the MF_SYSMENU flag. 
  648.  
  649.                 if (hMenuPopup == GetSubMenu(GetMenu(pfrm->hWnd), 0))
  650.                     flags |= MF_SYSMENU;
  651.             }
  652.  
  653.             // Make active MDI Child think that it received the     
  654.             // WM_MENUSELECT message. 
  655.  
  656.             FORWARD_WM_MENUSELECT(
  657.                                      pfrm->hWndActiveMDIChild,
  658.                                      hMenu, item, hMenuPopup,
  659.                                      flags,
  660.                                      SendMessage);
  661.  
  662.             wTemp = 0;                    // MDI Child handled the message. 
  663.             break;
  664.         }
  665.  
  666.         // Calculate the index of the top-level menu. 
  667.  
  668.         hMenu = GetMenu(pfrm->hWnd);
  669.         wTemp = GetMenuItemCount(hMenu);
  670.  
  671.         while (wTemp--)
  672.             if (GetSubMenu(hMenu, wTemp) == hMenuPopup)
  673.                 break;
  674.  
  675.         wTemp += IDS_FRAMEPOPUPID + 1;    // Jump over system menu. 
  676.         break;
  677.  
  678.     case MF_SYSMENU:
  679.         // item is menu item ID from system menu. 
  680.         wTemp = IDS_FRAMEMENUID + ((item & 0x0FFF) >> 4);
  681.         break;
  682.  
  683.     case MF_POPUP | MF_SYSMENU:
  684.         // item is handle to app's sys menu. 
  685.         wTemp = IDS_FRAMEPOPUPID;
  686.         break;
  687.     }
  688.  
  689.     // If message handled by MDI Child, nothing more to do. 
  690.  
  691.     if (wTemp != 0) {
  692.         // Tell the Frame that the Frame window should display the    
  693.         // help text and the identifier for the help text. 
  694.  
  695.         SendMessage(pfrm->hWnd, FW_SETMENUHELP,
  696.                     (WPARAM) pfrm->hWnd, (LPARAM) wTemp);
  697.     }
  698. }
  699.  
  700. void Frame_OnEnterIdle(FRAME * pfrm, WORD source, HWND hWndSource)
  701. {
  702.     RECT            rc;
  703.     PAINTSTRUCT        ps;
  704.  
  705.     if (source == MSGF_MENU) {
  706.         // User has stopped scrolling through menu items. 
  707.  
  708.         // If Menu help already displayed, nothing more to do. 
  709.         // This is signaled by hWndMenu help being -1. 
  710.  
  711.         if (pfrm->hWndMenuHelp != (HWND) - 1) {
  712.             // Display new menu help, invalidate the status bar. 
  713.  
  714.             SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rc));
  715.             InvalidateRect(pfrm->hWnd, &rc, TRUE);
  716.  
  717.             // BeginPaint is OK because an invalid rectangle must exist because 
  718.             // of the call to InvalidateRect above.     This causes the background 
  719.             // for the Frame's client area to be drawn correctly. 
  720.  
  721.             BeginPaint(pfrm->hWnd, &ps);
  722.  
  723.             // Set up the device context. 
  724.  
  725.             SetBkMode(ps.hdc, TRANSPARENT);
  726.  
  727.             // Send message to window that last received a WM_MENUSELECT 
  728.             // message to tell it to paint the status bar with the    
  729.             // appropriate menu help text. 
  730.  
  731.             SendMessage(pfrm->hWndMenuHelp, AW_PAINTMENUHELP, 0,
  732.                         (LPARAM)((LPPAINTSTRUCT)&ps));
  733.  
  734.             EndPaint(pfrm->hWnd, &ps);
  735.  
  736.             // Set flag notifying this message that the most recently selected 
  737.             // menu item has had its help text painted.     This stops unsightly 
  738.             // screen flicker. 
  739.  
  740.             pfrm->hWndMenuHelp = (HWND) - 1;
  741.         }
  742.     }
  743. }
  744.  
  745.  
  746. void Frame_OnMdiChildDestroy(FRAME * pfrm)
  747. //----------------------------------------------------------------- 
  748. // Message is posted by an MDI Child just before it is destroyed. 
  749. //----------------------------------------------------------------- 
  750. {
  751.     // If another MDI Child exists, nothing to do. 
  752.  
  753.     if (pfrm->hWndActiveMDIChild != NULL)
  754.         return;
  755.  
  756.     // Set the menu bar and accelerator table to the Frame's defaults. 
  757.  
  758.     Frame_ChangeMDIMenu(   pfrm->hWnd,
  759.                            pfrm->hWndClient,
  760.                            pfrm->hMenu,
  761.                            CMD_WINDOWTILEVERT);
  762.  
  763.     g_app.hAccelTable = NULL;
  764.  
  765.     // Force the status bar to be updated. 
  766.  
  767.     InvalidateRect(pfrm->hWnd, NULL, TRUE);
  768.  
  769.     // Disable the Ribbon. 
  770.  
  771.     EnableWindow(pfrm->hdlgRibbon, FALSE);
  772. }
  773.  
  774. void Frame_OnGetStatBarRect(FRAME * pfrm, LPRECT lpRect)
  775. {
  776.     // Get the client area of the Frame window. 
  777.  
  778.     GetClientRect(pfrm->hWnd, lpRect);
  779.  
  780.     // If the status bar is OFF, set the status bar to have no height. 
  781.  
  782.     if (pfrm->fStatusBarOn) {
  783.         // Change the dimensions so that the status bar is the height of  
  784.         // one line of text plus a small border. 
  785.  
  786.         HDC                hdc;
  787.         TEXTMETRIC        tm;
  788.  
  789.         hdc = GetDC(pfrm->hWnd);
  790.         GetTextMetrics(hdc, &tm);
  791.         ReleaseDC(pfrm->hWnd, hdc);
  792.  
  793.         lpRect->top = lpRect->bottom - tm.tmHeight -
  794.                 GetSystemMetrics(SM_CYBORDER);
  795.     }
  796.     else
  797.         lpRect->top = lpRect->bottom;
  798. }
  799.  
  800. void Frame_OnDrawStatusDivide(FRAME * pfrm, LPPAINTSTRUCT ps)
  801. {
  802.     HPEN            hPen;
  803.     DWORD            dwResult = GetSystemMetrics(SM_CYBORDER);
  804.  
  805.     // Draw a line separating the status bar from the MDICLIENT window. 
  806.  
  807.     hPen = CreatePen(PS_SOLID, (int) dwResult, RGB(0, 0, 0));
  808.     hPen = SelectPen(ps->hdc, hPen);
  809.  
  810.     MoveTo(ps->hdc, 0, ps->rcPaint.top);
  811.     LineTo(ps->hdc, ps->rcPaint.right, ps->rcPaint.top);
  812.     DeletePen(SelectPen(ps->hdc, hPen));
  813. }
  814.  
  815. void Frame_OnResizeMdiClient(FRAME * pfrm)
  816. {
  817.     RECT            rc, rcTemp;
  818.  
  819.     // Sent when the Frame window is resized or when the status bar     
  820.     // and ribbon are toggled. 
  821.  
  822.     GetClientRect(pfrm->hWnd, &rc);
  823.  
  824.     if (IsWindow(pfrm->hdlgRibbon) && IsWindowVisible(pfrm->hdlgRibbon)) {
  825.         // Ribbon is displayed, adjust rectangle. 
  826.  
  827.         GetClientRect(pfrm->hdlgRibbon, &rcTemp);
  828.         rc.top += rcTemp.bottom;
  829.         rc.bottom -= rcTemp.bottom;
  830.     }
  831.  
  832.     // Get the dimensions of the status bar rectangle and adjust the  
  833.     // dimensions of the MDICLIENT window. 
  834.  
  835.     SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rcTemp));
  836.     rc.bottom -= rcTemp.bottom - rcTemp.top;
  837.     MoveWindow(pfrm->hWndClient, 0, rc.top, rc.right, rc.bottom, TRUE);
  838. }
  839.  
  840. void Frame_OnSetMenuHelp(FRAME * pfrm, HWND hWndMenuHelp, DWORD dwMenuHelp)
  841. //----------------------------------------------------------------- 
  842. // Called by the Frame and MDI Children whenever a    
  843. // WM_MENUSELECT message is received. 
  844. //----------------------------------------------------------------- 
  845. {
  846.     // Save the handle of the window sending the message. 
  847.  
  848.     pfrm->hWndMenuHelp = hWndMenuHelp;
  849.  
  850.     // Save the menu help code that the window sent too. 
  851.  
  852.     pfrm->dwMenuHelp = dwMenuHelp;
  853.  
  854.     // When the Frame or MDI Child receive a WM_MENUSELECT message 
  855.     // specifying that the menu system is closed  
  856.     // (dwMenuHelp == MAKELONG(-1, 0)), the menu help should disappear and 
  857.     // be replaced by the proper information on the status bar. 
  858.  
  859.     if (hWndMenuHelp == NULL) {
  860.         RECT            rc;
  861.  
  862.         SendMessage(pfrm->hWnd, FW_GETSTATBARRECT, 0, (LPARAM)((LPRECT)&rc));
  863.  
  864.         // Force status bar to be updated. 
  865.  
  866.         InvalidateRect(pfrm->hWnd, &rc, TRUE);
  867.     }
  868. }
  869.  
  870. DWORD Frame_OnGetMenuHelp(FRAME * pfrm)
  871. //----------------------------------------------------------------- 
  872. // Sent by the Frame or MDI Child when they     
  873. // receive a AW_PAINTMENUHELP message. 
  874. //----------------------------------------------------------------- 
  875. {
  876.     return pfrm->dwMenuHelp;
  877. }
  878.  
  879. void Frame_OnPaintMenuHelp(FRAME * pfrm, LPPAINTSTRUCT psStatus)
  880. //----------------------------------------------------------------- 
  881. // Message sent from Frame window to notify Frame that it should 
  882. // paint the status bar text for the last highlighted menu item. 
  883. //----------------------------------------------------------------- 
  884. {
  885.     LRESULT            lResult;
  886.  
  887.     // Ask the Frame window what the last selected menu ID was. 
  888.     // This value was sent to the frame by this window during the  
  889.     // processing for the WM_MENUSELECT message. 
  890.  
  891.     lResult = SendMessage(pfrm->hWnd, FW_GETMENUHELP, 0, 0);
  892.  
  893.     // Draw the horizontal dividing line separating the Status bar 
  894.     // from the MDICLIENT window. 
  895.  
  896.     psStatus->rcPaint.top += (int)
  897.             SendMessage(pfrm->hWnd, FW_DRAWSTATUSDIVIDE, 0, (LPARAM) psStatus);
  898.  
  899.     // Construct the string that is to be displayed. 
  900.  
  901.     LoadString(g_app.hinst, LOWORD(lResult), g_app.szBuf, sizeof(g_app.szBuf));
  902.  
  903.     // Paint the menu help text in the status bar. 
  904.  
  905.     TextOut(psStatus->hdc, 0, psStatus->rcPaint.top, g_app.szBuf, lstrlen(g_app.szBuf));
  906. }
  907.  
  908. //-Utility routines------------------------------------------------ 
  909.  
  910. HWND WINAPI Frame_CreateMDIChild(LPSTR szClassName,
  911.                                  LPSTR szWindowName,
  912.                                  DWORD dwStyle,
  913.                                  short x,
  914.                                  short y,
  915.                                  short nWidth,
  916.                                  short nHeight,
  917.                                  HWND hWndMDIClient,
  918.                                  HANDLE hInstance,
  919.                                  LONG lParam)
  920. {
  921.     MDICREATESTRUCT cs;
  922.     HWND            hWndChild;
  923.  
  924.     cs.szClass = szClassName;
  925.     cs.szTitle = szWindowName;
  926.     cs.hOwner = hInstance;
  927.     cs.x = x;
  928.     cs.y = y;
  929.     cs.cx = nWidth;
  930.     cs.cy = nHeight;
  931.     cs.style = dwStyle;
  932.     cs.lParam = lParam;
  933.  
  934.     hWndChild = (HWND) SendMessage(hWndMDIClient, WM_MDICREATE,
  935.             0, (LPARAM)((LPMDICREATESTRUCT)&cs));
  936.     return (hWndChild);
  937. }
  938.  
  939. // Function to change the menu in the Frame window whenever a  
  940. // new MDI Child becomes active. 
  941.  
  942. void WINAPI Frame_ChangeMDIMenu(HWND hWndFrame,
  943.                                 HWND hWndClient,
  944.                                 HMENU hMenuNew,
  945.                                 WORD wMenuID)
  946. {
  947.     WORD            wCount;
  948.     HMENU            hSubMenu = 0;
  949.  
  950.     // Get number of top-level menu items in the menu used by the window 
  951.     // being activated. 
  952.  
  953.     wCount = GetMenuItemCount(hMenuNew);
  954.  
  955.     // Locate the POPUP menu that contains the menu option with the     
  956.     // 'wMenuID' identifier in it.    This must be an identifier for an option 
  957.     // in the new menu's "Window" popup menu. 
  958.  
  959.     while (wCount) {
  960.         hSubMenu = GetSubMenu(hMenuNew, wCount - 1);
  961.         if ((int) GetMenuState(hSubMenu, wMenuID, MF_BYCOMMAND) != -1)
  962.             break;
  963.         wCount--;
  964.     }
  965.  
  966.     // Tell the MDICLIENT window to setup the new menu. 
  967.  
  968.     SendMessage(hWndClient, WM_MDISETMENU, 0, MAKELONG(hMenuNew, hSubMenu));
  969.     DrawMenuBar(hWndFrame);
  970. }
  971.  
  972. void WINAPI Frame_TileVertically(HWND hWndMDIClient)
  973. {
  974.     int    nNumWndsOnRow, nOpenMDIChildren = 0, nTopOfBottomIconRow = 0;
  975.     int    nCrntCol, nColWidth, nCrntRow, nNumRows, nRowHeight, nMinWndHeight;
  976.     HWND            hWndChild;
  977.     HANDLE            hWinPosInfo;
  978.     RECT            rc;
  979.     POINT            Point;
  980.     DWORD            dwChildInfo;
  981.  
  982.     // Assume that scrollbars will be off after windows are tiled. 
  983.     // By forcing them off now, GetClientRect will return the correct size. 
  984.  
  985.     ShowScrollBar(hWndMDIClient, SB_BOTH, 0);
  986.  
  987.     // The WM_MDICASCADE and WM_MDITILE messages cause the icons to be    
  988.     // arranged.  So we will too.  In fact, this is necessary to locate     
  989.     // the top of the bottom icon row in the next step of this function. 
  990.  
  991.     SendMessage(hWndMDIClient, WM_MDIICONARRANGE, 0, 0);
  992.  
  993.     // Get handle to first MDI Child window. 
  994.  
  995.     hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
  996.  
  997.     do {
  998.         if (IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
  999.             // Window is iconic and window is NOT an icon's caption. 
  1000.  
  1001.             // Get client area of the icon window. 
  1002.  
  1003.             GetWindowRect(hWndChild, &rc);
  1004.  
  1005.             // rc.top is in screen coordinates. 
  1006.  
  1007.             nTopOfBottomIconRow = max(nTopOfBottomIconRow, rc.top);
  1008.         }
  1009.  
  1010.         if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL)
  1011.             ++nOpenMDIChildren;
  1012.  
  1013.     }
  1014.     while ((hWndChild = GetWindow(hWndChild, GW_HWNDNEXT)) != NULL);
  1015.  
  1016.  
  1017.     // All MDI Children are icons, no tiling is necessary. 
  1018.  
  1019.     if (nOpenMDIChildren == 0)
  1020.         return;
  1021.  
  1022.  
  1023.     // Find height of usable client area for tiling. 
  1024.  
  1025.     GetClientRect(hWndMDIClient, &rc);
  1026.  
  1027.     if (nTopOfBottomIconRow) {
  1028.         // At least one MDI Child is iconic. 
  1029.  
  1030.         // Convert coordinates from screen to client. 
  1031.  
  1032.         Point.x = 0;
  1033.         Point.y = nTopOfBottomIconRow;
  1034.         ScreenToClient(hWndMDIClient, &Point);
  1035.  
  1036.         // Point.y is top of bottom icon row in client coordinates. 
  1037.  
  1038.         rc.bottom = Point.y;
  1039.     }
  1040.  
  1041.  
  1042.     // Restore the active MDI child if it's maximized 
  1043.  
  1044.     dwChildInfo = SendMessage(hWndMDIClient, WM_MDIGETACTIVE, 0, 0);
  1045.  
  1046.     if (HIWORD(dwChildInfo) == 1)
  1047.         ShowWindow((HWND) LOWORD(dwChildInfo), SW_RESTORE);
  1048.  
  1049.     // Calculate the minimum desired height of each MDI Child. 
  1050.  
  1051.     nMinWndHeight = max(1, rc.bottom / (5 * GetSystemMetrics(SM_CYCAPTION)));
  1052.  
  1053.     // Calculate the number of rows that will be tiled. 
  1054.  
  1055.     nNumRows = min(nOpenMDIChildren, nMinWndHeight);
  1056.  
  1057.     // Calculate the height of each row. 
  1058.  
  1059.     nRowHeight = rc.bottom / nNumRows;
  1060.  
  1061.     // Get the handle to the first MDI Child window. 
  1062.  
  1063.     hWndChild = GetWindow(hWndMDIClient, GW_CHILD);
  1064.  
  1065.     // Prime the storage of positioning information. 
  1066.  
  1067.     hWinPosInfo = BeginDeferWindowPos(nOpenMDIChildren);
  1068.  
  1069.     // Execute the loop for each row. 
  1070.  
  1071.     for (nCrntRow = 0; nCrntRow < nNumRows; nCrntRow++) {
  1072.         // Calculate the number of MDI Children that will appear on this row. 
  1073.  
  1074.         nNumWndsOnRow = nOpenMDIChildren / nNumRows +
  1075.                 ((nOpenMDIChildren % nNumRows > (nNumRows - (nCrntRow + 1))) ? 1 : 0);
  1076.  
  1077.         // Calculate the width of each of these children. 
  1078.  
  1079.         nColWidth = rc.right / nNumWndsOnRow;
  1080.  
  1081.         // Fill each column with an MDI Child window. 
  1082.  
  1083.         for (nCrntCol = 0; nCrntCol < nNumWndsOnRow;) {
  1084.             if (!IsIconic(hWndChild) && GetWindow(hWndChild, GW_OWNER) == NULL) {
  1085.                 // Child is NOT iconic and not an icon's caption bar. 
  1086.  
  1087.                 // Tell windows what the new position and dimensions of this  
  1088.                 // MDI Child should be. 
  1089.  
  1090.                 hWinPosInfo = DeferWindowPos(hWinPosInfo, hWndChild, NULL,
  1091.                        nCrntCol * nColWidth, nCrntRow * nRowHeight, nColWidth,
  1092.                                    nRowHeight, SWP_NOACTIVATE | SWP_NOZORDER);
  1093.  
  1094.                 // Go to the next column. 
  1095.  
  1096.                 nCrntCol++;
  1097.             }
  1098.  
  1099.             // Get handle to the next MDI Child window. 
  1100.  
  1101.             hWndChild = GetWindow(hWndChild, GW_HWNDNEXT);
  1102.         }
  1103.     }
  1104.  
  1105.     // All of the positioning has been set.     Now, tell Windows to update 
  1106.     // all of the windows at once. 
  1107.  
  1108.     EndDeferWindowPos(hWinPosInfo);
  1109. }
  1110.